﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using MyBasicLib.Utilities.Log;
using MyBasicLib.Utilities;

namespace MyBasicLib.Data.ORMLiteNew
{
    /// <summary>
    /// 数据访问入口 
    /// </summary>
    public sealed class DataContext : IDisposable
    {

        /// <summary>
        /// 数据访问提供程序
        /// </summary>
        public IDbQueryProvider Provider { get; set; }

        /// <summary>
        /// 用于延迟执行Insert,Delete,Update操作
        /// </summary>
        //private readonly List<IDbQueryable> querys = new List<IDbQueryable>();
        private readonly List<Func<IDbCommand>> cmds = new List<Func<IDbCommand>>();

        #region 构造函数

        public DataContext()
            : this(IOC.DefaultContainer.Resolve<IDbQueryProvider>())
        {
        }
        public DataContext(string connectionString)
            : this(IOC.DefaultContainer.Resolve<IDbQueryProvider>(), connectionString)
        {
        }
        public DataContext(IDbQueryProvider provider, string connectionString = null)
        {
            Provider = provider;
            if (!string.IsNullOrEmpty(connectionString))
            {
                Provider.Executor.ConnectionString = connectionString;
            }
        }

        #endregion

        /// <summary>
        /// The time (in seconds) to wait for the command to execute. The default value   is 30 seconds.
        /// </summary>
        public int CommandTimeout { get; set; }


        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">实体</param>
        public void Insert<T>(T value) //where T : ITable
        {
            IDbQueryable<T> iq = GetTable<T>();
            iq.DbExpressionList.Add(new DbExpression(DbExpressionType.Insert, System.Linq.Expressions.Expression.Constant(value)));

            lock (cmds)
            {
                //querys.Add(iq);
                cmds.Add(() => iq.CreateCommand());
            }
        }
        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">实体列表</param>
        public void Insert<T>(IEnumerable<T> values) //where T : ITable
        {
            lock (cmds)
            {
                foreach (T value in values)
                {
                    IDbQueryable<T> iq = GetTable<T>();
                    iq.DbExpressionList.Add(new DbExpression(DbExpressionType.Insert, System.Linq.Expressions.Expression.Constant(value)));
                    //querys.Add(iq);
                    cmds.Add(() => iq.CreateCommand());
                }
            }
        }
        /// <summary>
        /// 新增从查询里
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">查询</param>
        public void Insert<T>(IDbQueryable<T> query) //where T : ITable
        {
            IDbQueryable<T> iq = query;
            iq.DbExpressionList.Add(new DbExpression(DbExpressionType.Insert));

            lock (cmds)
            {
                //querys.Add(iq);
                cmds.Add(() => iq.CreateCommand());
            }
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate">条件</param>
        public void Delete<T>(Expression<Func<T, bool>> predicate)// where T : ITable
        {
            Delete<T>(p => p.Where(predicate));
        }

        private void Delete<T>(Func<IDbQueryable<T>, IDbQueryable<T>> predicate) //where T : ITable
        {
            IDbQueryable<T> iq = GetTable<T>();
            IDbQueryable<T> newIq = predicate(iq);
            Delete(newIq);
        }
        /// <summary>
        /// 删除从查询里
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query">查询</param>
        public void Delete<T>(IDbQueryable<T> query) //where T : ITable
        {
            query.DbExpressionList.Add(new DbExpression(DbExpressionType.Delete));

            lock (cmds)
            {
                //querys.Add(query);
                cmds.Add(() => query.CreateCommand());
            }
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="newValue">实体</param>
        public void Update<T>(T newValue) //where T : ITable
        {
            IDbQueryable<T> iq = GetTable<T>();
            iq.DbExpressionList.Add(new DbExpression(DbExpressionType.Update, Expression.Constant(newValue)));

            lock (cmds)
            {
                //querys.Add(iq);
                cmds.Add(() => iq.CreateCommand());
            }
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action">要更新的字段</param>
        /// <param name="predicate">条件</param>
        public void Update<T>(Expression<Func<T, T>> action, Expression<Func<T, bool>> predicate) //where T : ITable
        {
            Update(action, p => p.Where(predicate));
        }

        private void Update<T>(Expression<Func<T, T>> action, Func<IDbQueryable<T>, IDbQueryable<T>> predicate)
        //where T : ITable
        {
            IDbQueryable<T> iq = GetTable<T>();
            IDbQueryable<T> newIq = predicate(iq);
            Update(action, newIq);
        }
        /// <summary>
        /// 更新从查询里
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action">要更新的字段</param>
        /// <param name="query">查询</param>
        public void Update<T>(Expression<Func<T, T>> action, IDbQueryable<T> query)// where T : ITable
        {
            query.DbExpressionList.Add(new DbExpression(DbExpressionType.Update, action));

            lock (cmds)
            {
                //querys.Add(query);
                cmds.Add(() => query.CreateCommand());
            }
        }
        /// <summary>
        /// 提交事务
        /// </summary>
        /// <returns>影响记录数量</returns>
        public int SubmitChanges()
        {
            int affected = 0;
            if (cmds.Count < 1) return 0;
            lock (cmds)
            {
                if (cmds.Count < 1) return 0;
                var list = new List<IDbCommand>(cmds.Count);
                list.AddRange(cmds.Select(p => p()));
                if (System.Transactions.Transaction.Current == null)
                {
                    affected = ExecuteWithTransaction(list);
                }
                else
                {
                    affected = ExecuteWithNoTransaction(list);
                }
                return affected;
            }
        }

        private int ExecuteWithTransaction(List<IDbCommand> list)
        {
            var affected = 0;
            using (IDbConnection conn = this.Provider.Executor.CreateNewOpenConnection())
            {
                if (conn == null) return 0;
                using (IDbTransaction trans = conn.BeginTransaction(IsolationLevel.ReadCommitted))
                {
                    IDbCommand theCmd = null;
                    try
                    {
                        foreach (IDbCommand cmd in list)
                        {
                            theCmd = cmd;
                            affected += Provider.Executor.ExecuteNonQuery(trans, cmd);
                        }
                        trans.Commit();
                        cmds.Clear();
                    }
                    catch (Exception ex)
                    {
                        trans.Rollback();
                        IOC.DefaultContainer.Resolve<ILogger>().Error(ex.ToString());
                        if (theCmd != null)
                            throw new DbCommandException(ex.Message, ex) { DbCommand = theCmd };
                        else throw;
                    }
                }
            }
            return affected;
        }

        private int ExecuteWithNoTransaction(List<IDbCommand> list)
        {
            var affected = 0;
            try
            {
                foreach (IDbCommand cmd in list)
                {
                    affected += Provider.Executor.ExecuteNonQuery(null, cmd);
                }
                cmds.Clear();
            }
            catch (Exception ex)
            {
                IOC.DefaultContainer.Resolve<ILogger>().Error(ex.ToString());
                throw;
            }
            return affected;
        }
        /// <summary>
        /// 取消事务
        /// </summary>
        public void DiscardChanges()
        {
            lock (cmds)
            {
                cmds.Clear();
            }
        }
        /// <summary>
        /// 查询某个表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IDbQueryable<T> GetTable<T>() //where T : ITable
        {
            var q = new DbQueryable<T>() { Provider = Provider };
            q.DbExpressionList = new List<DbExpression>() { new DbExpression( DbExpressionType.GetTable, 
              System.Linq.Expressions.Expression.Constant(typeof(T)) ) };
            return q;
        }


        public void Dispose()
        {
            DiscardChanges();
        }
    }
}